package com.ds.duizhang1;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.ds.duizhang1.dto.支付宝ExcelDTO;
import com.ds.duizhang1.dto.银行流水ExcelDTO;
import com.ds.duizhang1.util.Util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class Handle {
    static SimpleDateFormat simpleDateFormatSource = new SimpleDateFormat("yyyy/M/dd");
    static SimpleDateFormat simpleDateFormatSource2 = new SimpleDateFormat("yyyy-MM-dd");
    static SimpleDateFormat simpleDateFormatTarget = new SimpleDateFormat("yyyy-MM-dd");

    public static void main(String[] args) {
        String fileName = "C:\\ds\\气泡\\个人卡和公司卡银行打款记录1101.xlsx";
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        // 这里每次会读取100条数据 然后返回过来 直接调用使用数据就行
//        EasyExcel.read(fileName, 银行流水ExcelDTO.class, new PageReadListener<银行流水ExcelDTO>(dataList -> {
//            for (银行流水ExcelDTO demoData : dataList) {
//                log.info("读取到一条数据{}", JSON.toJSONString(demoData));
//            }
//        })).sheet().doRead();

        List<银行流水ExcelDTO> 银行流水 = new LinkedList<>();
        List<支付宝ExcelDTO> 支付宝流水 = new LinkedList<>();

        //尝试读取缓存
        try {
            log.info("正在读缓存数据---------");
            银行流水 = Util.readBankDataFromCache();
            支付宝流水 = Util.readZfbDataFromCache();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (CollectionUtils.isEmpty(银行流水)) {
            try (ExcelReader excelReader = EasyExcel.read(fileName).build()) {
                List<银行流水ExcelDTO> final银行流水 = 银行流水;
                ReadSheet sheet银行 = EasyExcel.readSheet(0)
                        .head(银行流水ExcelDTO.class)
                        .headRowNumber(6)
                        .registerReadListener(new PageReadListener<银行流水ExcelDTO>(dataList -> {
                            log.info("正在读银行流水---------" + dataList.size());
                            for (银行流水ExcelDTO data : dataList) {
//                            log.info("读取到一条数据{}", JSON.toJSONString(data));
                                final银行流水.add(data);
                            }
                        }))
                        .build();

                List<支付宝ExcelDTO> final支付宝流水 = 支付宝流水;
                ReadSheet sheet支付宝 = EasyExcel.readSheet(1)
                        .head(支付宝ExcelDTO.class)
                        .headRowNumber(6)
                        .registerReadListener(new PageReadListener<支付宝ExcelDTO>(dataList -> {
                            log.info("正在读支付宝流水---------" + dataList.size());
                            for (支付宝ExcelDTO data : dataList) {
//                            log.info("读取到一条数据{}", JSON.toJSONString(data));
                                final支付宝流水.add(data);
                            }
                        }))
                        .build();
                excelReader.read(sheet银行, sheet支付宝);
            }
            //尝试缓存
            try {
                Util.writeBankData2Local(银行流水);
                Util.writeZfbData2Local(支付宝流水);
                log.info("-----缓存数据成功--------");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


        log.info("数据分组--------");
        Map<String, List<银行流水ExcelDTO>> 银行流水日期分组 = 银行流水.stream()
//                .filter(dto -> "徐树源个人卡-稠州银行2022年".equals(dto.get转账方式()))
                .filter(dto -> Objects.nonNull(dto.get交易日期()))
                //交易日期分组, 格式: 2022-01-01
                .collect(Collectors.groupingBy(银行流水ExcelDTO::get交易日期));


        Map<String, List<支付宝ExcelDTO>> 支付宝流水日期分组 = 支付宝流水.stream()
                //交易日期分组, 原格式: 2022/4/14 14:59  转2022-01-01
                .collect(Collectors.groupingBy(dto -> parseDateString(dto.get交易时间())));

        //日期对账
        log.info("==============开始对账==================");
        银行流水日期分组.entrySet().stream()
                .sorted(Comparator.comparing(Map.Entry::getKey))
                .forEach(bankDataEntry -> {
                    String dateString = bankDataEntry.getKey();
                    对账(dateString, bankDataEntry.getValue(), 支付宝流水日期分组.get(dateString));
                });

        //银行流水多的

        //支付宝流水多的


    }


    /**
     * 银行与支付宝对账
     *
     * @param dateString
     * @param bankDatas
     * @param zfbDatas
     */
    private static void 对账(String dateString, List<银行流水ExcelDTO> bankDatas, List<支付宝ExcelDTO> zfbDatas) {
        BigDecimal 银行当日总账 = BigDecimal.ZERO;
        BigDecimal 支付宝当日总账 = BigDecimal.ZERO;
        if (CollectionUtils.isEmpty(zfbDatas)) {
            log.warn("日期{} :支付宝没有该日期的数据,不对账" , dateString);
            return;
        }
        try {
            //银行当日总账 支出, 带-号
            银行当日总账 = bankDatas.stream()
                    .filter(bank -> "支付宝（中国）网络技术有限公司".equals(bank.get对方名称()))
                    .map(data -> parseBigDecimal(data.get支出()))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        } catch (Exception e) {
            log.warn("日期{} :银行当日数据异常,对账失败, 异常原因:{}", dateString, e.getMessage());
            return;
        }

        try {
            支付宝当日总账 = zfbDatas.stream()
//                    .filter(data -> "浙江稠州商业银行储蓄卡(3172)".equals(data.get收付款方式()))
                    .filter(data -> StringUtils.startsWith(data.get收付款方式(),"浙江稠州商业银行储蓄卡(3172)"))
                    .map(data -> parerZFBAmount(data))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        } catch (Exception e) {
            log.warn("日期{} :支付宝当日数据异常,对账失败, 异常原因:{}", dateString, e.getMessage());
            return;
        }

        BigDecimal 差额银行_支付宝 = 银行当日总账.subtract(支付宝当日总账);
        if (!BigDecimal.ZERO.equals(银行当日总账)
                && 差额银行_支付宝.abs().compareTo(BigDecimal.TEN) < 0) {
            log.warn("日期{} :-------   ok   -------   银行={},支付宝={}", dateString, 银行当日总账, 支付宝当日总账);
            return;
        }

        //当日账不平
        log.warn("日期{} :账不平,差额={},银行={},支付宝={}", dateString, 差额银行_支付宝, 银行当日总账, 支付宝当日总账);


    }

    /**
     * 分析支付宝流水正确性
     *
     */
    private static void 分析支付宝流水正确性(List<支付宝ExcelDTO> zfbDatas) {
        log.info("============== 分析支付宝流水正确性 ==================");
        List<支付宝ExcelDTO> d1 = zfbDatas;
        List<支付宝ExcelDTO> d2 = zfbDatas.stream().collect(Collectors.toList());
        for (支付宝ExcelDTO d : d1) {
            //如果是退款,则必须有原单
        }


    }

    /**
     * 支付宝流水没有进出的区别, 需要处理
     * 收支方式为"支出"的,一般为支出,记为-
     * ** 特别:如果"交易分类"="转账红包"且交易状态"未领取，已退回", 就是银行第二天又收回去了
     * 这里判断的场景是支付宝作为银行的中转,所以进账出账记录为跟银行一致.
     *
     * @param data
     * @return
     */
    private static BigDecimal parerZFBAmount(支付宝ExcelDTO data) {

        BigDecimal amount = parseBigDecimal(data.get金额());
        if ("支出".equals(data.get收支())) {
            amount = amount.multiply(new BigDecimal(-1));
        }
        return amount;
    }

    private static BigDecimal parseBigDecimal(String s) {
        if (StringUtils.contains(s, ",")) {
            s = StringUtils.replace(s, ",", "");
        }
        return new BigDecimal(s);
    }


    private static String parseDateString(String 交易时间) {
        if (StringUtils.isBlank(交易时间)) {
            return "blankDate";
        }
        Date date = null;
        try {
            date = simpleDateFormatSource.parse(交易时间);
        } catch (Exception e) {
            try {
                date = simpleDateFormatSource2.parse(交易时间);
            } catch (Exception e2) {
                return "交易时间不正确,原因=" + e.getMessage();
            }
        }
        return simpleDateFormatTarget.format(date);
    }


}
